package yunjiao.springboot.autoconfigure.captcha;

import cn.hutool.captcha.ICaptcha;
import cn.hutool.core.lang.Assert;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import yunjiao.springboot.extension.captcha.hutool.*;
import yunjiao.springboot.extension.common.captcha.CaptchaService;

import java.awt.*;
import java.util.Optional;

/**
 * Hutool验证码配置
 *
 * @author yangyunjiao
 */
@Slf4j
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ICaptcha.class})
@EnableConfigurationProperties({HutoolCaptchaProperties.class})
public class HutoolCaptchaConfiguration {
    /**
     * {@link PostConstruct} 注解方法
     */
    @PostConstruct
    public void postConstruct() {
        log.info("Hutool Captcha Configuration");
    }

    @Bean
    CaptchaService lineCaptchaService(HutoolCaptchaProperties properties) {
        HutoolCaptchaProperties.DrawingOptions options = properties.getLine();
        validate(options);
        Font font = createFont(options.getFont());

        LineCaptchaBuilder lcb = new LineCaptchaBuilder();
        fillBuilder(lcb, options);

        LineCaptchaService service = new LineCaptchaService(lcb);
        if (log.isDebugEnabled()) {
            log.debug("Configure Bean [Line Captcha Service -> {}]", service);
        }
        return service;
    }

    @Bean
    CaptchaService circleCaptchaService(HutoolCaptchaProperties properties) {
        HutoolCaptchaProperties.DrawingOptions options = properties.getCircle();
        validate(options);

        CircleCaptchaBuilder ccb = new CircleCaptchaBuilder();
        fillBuilder(ccb, options);

        CircleCaptchaService service = new CircleCaptchaService(ccb);
        if (log.isDebugEnabled()) {
            log.debug("Configure Bean [Circle Captcha Service -> {}]", service);
        }
        return service;
    }

    @Bean
    CaptchaService sheareCaptchaService(HutoolCaptchaProperties properties) {
        HutoolCaptchaProperties.DrawingOptions options = properties.getShear();
        validate(options);

        ShearCaptchaBuilder scb = new ShearCaptchaBuilder();
        fillBuilder(scb, options);

        ShearCaptchaService service = new ShearCaptchaService(scb);
        if (log.isDebugEnabled()) {
            log.debug("Configure Bean [Shear Captcha Service -> {}]", service);
        }
        return service;
    }


    @Bean
    CaptchaService gifCaptchaService(HutoolCaptchaProperties properties) {
        HutoolCaptchaProperties.GifDrawingOptions options = properties.getGif();
        validate(options);
        Assert.isTrue(options.getQuality() >= 1 && options.getQuality() <= 20, "验证码配置属性‘quality‘值必须在[1, 20]之间");
        Assert.isTrue(options.getRepeat() >= 0, "验证码配置属性‘repeat‘值必须大于0");
        Assert.isTrue(options.getMinColor() >= 0 && options.getMinColor() <= 255, "验证码配置属性‘minColor‘值必须在[0, 255]之间");
        Assert.isTrue(options.getMaxColor() >= 0 && options.getMaxColor() <= 255, "验证码配置属性‘maxColor‘值必须在[0, 255]之间");

        GifCaptchaBuilder gcb = new GifCaptchaBuilder();
        fillBuilder(gcb, options);
        gcb.setQuality(options.getQuality());
        gcb.setRepeat(options.getRepeat());
        gcb.setMinColor(options.getMinColor());
        gcb.setMaxColor(options.getMaxColor());

        GifCaptchaService service = new GifCaptchaService(gcb);
        if (log.isDebugEnabled()) {
            log.debug("Configure Bean [Gif Captcha Service -> {}]", service);
        }
        return service;
    }

    private void validate(HutoolCaptchaProperties.DrawingOptions drawing) {
        Assert.isTrue(drawing.getWidth() > 0, "验证码配置属性‘width‘值必须大于0");
        Assert.isTrue(drawing.getHeight() > 0, "验证码配置属性‘height‘值必须大于0");
        Assert.isTrue(drawing.getInterfereCount() > 0, "验证码配置属性‘interfereCount‘值必须大于0");

        Optional.ofNullable(drawing.getTransparency()).ifPresent(transparency ->
                Assert.isTrue(drawing.getTransparency() >= 0 && drawing.getTransparency() <= 1, "验证码配置属性‘transparency‘值必须在[0, 1]之间"));
        Optional.ofNullable(drawing.getFuzziness()).ifPresent(fuzziness ->
                Assert.isTrue(drawing.getFuzziness() >= 0 && drawing.getFuzziness() <= 30, "验证码配置属性‘fuzziness‘值必须在[0, 30]之间"));

        HutoolCaptchaProperties.CodeOptions code = drawing.getCode();
        Assert.isTrue(code.getLength() > 0, "验证码配置属性‘code.length‘值必须大于0");

        HutoolCaptchaProperties.FontOptions font = drawing.getFont();
        Assert.isTrue(font.getSize() > 0, "验证码配置属性‘font.size‘值必须大于0");
    }

    private void fillBuilder(AbstractCaptchaBuilder<?> builder, HutoolCaptchaProperties.DrawingOptions options) {
        Font font = createFont(options.getFont());

        builder.setWidth(options.getWidth());
        builder.setHeight(options.getHeight());
        builder.setInterfereCount(options.getInterfereCount());
        builder.setBackgroundColor(options.getBackgroundColor());
        builder.setFuzziness(options.getFuzziness());
        builder.setValidIgnoreCase(options.getValidIgnoreCase());
        builder.setFont(font);

        HutoolCaptchaProperties.CodeOptions code = options.getCode();
        builder.setGenerator(code.getGenerator().apply(code.getLength()));
    }

    @SuppressWarnings({"all"})
    private Font createFont(HutoolCaptchaProperties.FontOptions options) {
        return options.getName().getFont(options.getStyle().getMapping(), options.getSize());
    }
}
